<script setup>
import { ref, reactive } from 'vue'
// 初始化游戏数据
const data = {
    // board: reactive(
    //     Array(4)
    //         .fill(0)
    //         .map(() => Array(4).fill(0))
    // ),
    board: reactive([
        [2, 0, 0, 0],
        [0, 0, 0, 0],
        [0, 0, 0, 0],
        [0, 0, 0, 0]
    ]),
    score: ref(0)
}
const isZero = (i, j) => (data.board[i][j] == 0 ? 'hidden' : '')
/**
 * @function 获取新块
 * @return {object} result => {coordinate:坐标,value:值}
 */
function getNewBlock(matrix = data.board) {
    const [M, N] = [matrix.length, matrix[0].length]
    const emptyBlocks = []
    for (let i = 0; i < M; i++) {
        for (let j = 0; j < N; j++) {
            if (matrix[i][j] == 0) emptyBlocks.push([i, j])
        }
    }
    let i = Math.floor(Math.random() * emptyBlocks.length)
    const result = { coordinate: emptyBlocks[i], value: Math.random() < 0.5 ? 2 : 4 }
    matrix[result.coordinate[0]][result.coordinate[1]] = result.value
    return result
}
// 判断索引越界
function isInRange(i, j, matrix = data.board) {
    const [M, N] = [matrix.length, matrix[0].length]
    if (i >= 0 && i < M && j >= 0 && j < N) return true
    else return false
}
/**
 * @function 合并块
 * @param {string} direction 合并方向
 * @param {number} score 得分
 */
function mergeBlocks(direction, matrix = data.board, score = data.score) {
    console.log(direction)
    const [M, N] = [matrix.length, matrix[0].length]
    // 获取下一个元素坐标
    const next = {
        Up: (i, j) => [--i, j],
        Down: (i, j) => [++i, j],
        Left: (i, j) => [i, --j],
        Right: (i, j) => [i, ++j]
    }
    function mergeAline(i, j, direction) {
        console.log(i, j, direction)
        let [nextI, nextJ] = next[direction](i, j)
        while (isInRange(nextI, nextJ)) {
            console.log('try to merge')
            if (matrix[nextI][nextJ] == 0) [nextI, nextJ] = next[direction](nextI, nextJ)
            else if (matrix[i][j] == 0) {
                matrix[i][j] = matrix[nextI][nextJ]
                matrix[nextI][nextJ] = 0
                moved = true
            } else if (matrix[i][j] == matrix[nextI][nextJ]) {
                matrix[i][j] *= 2
                score.value += matrix[i][j]
                matrix[nextI][nextJ] = 0
                ;[i, j] = next[direction](i, j)
                moved = true
            } else {
                ;[i, j] = next[direction](i, j)
                if (i == nextI && j == nextJ) [nextI, nextJ] = next[direction](nextI, nextJ)
                else {
                    ;[matrix[i][j], matrix[nextI][nextJ]] = [matrix[nextI][nextJ], matrix[i][j]]
                    moved = true
                }
            }
        }
        console.log('mergedAline:', matrix)
    }
    let [i, j, moved] = [0, 0, false]
    switch (direction) {
        case 'Up':
            while (j < N) {
                mergeAline(i, j, 'Down')
                // ;[i, j] = next['Right'](i, j)
                j++
            }
            break
        case 'Down':
            i = M - 1
            while (j < N) {
                mergeAline(i, j, 'Up')
                // ;[i, j] = next['Right'](i, j)
                j++
            }
            break
        case 'Left':
            while (i < M) {
                mergeAline(i, j, 'Right')
                // ;[i, j] = next['Down'](i, j)
                i++
            }
            break
        case 'Right':
            j = N - 1
            while (i < M) {
                mergeAline(i, j, 'Left')
                // ;[i, j] = next['Down'](i, j)
                i++
            }
            break
    }
    console.log('after merged:', matrix)
    console.log('moved is:', moved)
    if (moved) {
        getNewBlock()
        console.log('createNewBlock')
    }
    // return movements
}
// 判断游戏结束
// function isOver(matrix = data.board) {
//     const [M, N] = [matrix.length, matrix[0].length]
//     for (let i = 0; i < M; i++) {
//         for (let j = 0; j < N; j++) {
//             if (matrix[i][j] == 0) return false
//             if (matrix[i][j] == matrix[i][j + 1] || matrix[i][j] == matrix[i + 1][j]) return false
//         }
//     }
//     return true
// }
// 更新视图
// function updateView(movements) {}
window.addEventListener('keydown', (event) => mergeBlocks(event.code.slice(5)))
</script>
<template>
    <div class="game">
        <div class="game-score">得分：{{ data.score }}</div>
        <div class="game-board">
            <div class="game-cell grid00">
                <div class="game-block" :class="isZero(0, 0)">{{ data.board[0][0] }}</div>
            </div>
            <div class="game-cell grid01">
                <div class="game-block" :class="isZero(0, 1)">{{ data.board[0][1] }}</div>
            </div>
            <div class="game-cell grid02">
                <div class="game-block" :class="isZero(0, 2)">{{ data.board[0][2] }}</div>
            </div>
            <div class="game-cell grid03">
                <div class="game-block" :class="isZero(0, 3)">{{ data.board[0][3] }}</div>
            </div>
            <div class="game-cell grid10">
                <div class="game-block" :class="isZero(1, 0)">{{ data.board[1][0] }}</div>
            </div>
            <div class="game-cell grid11">
                <div class="game-block" :class="isZero(1, 1)">{{ data.board[1][1] }}</div>
            </div>
            <div class="game-cell grid12">
                <div class="game-block" :class="isZero(1, 2)">{{ data.board[1][2] }}</div>
            </div>
            <div class="game-cell grid13">
                <div class="game-block" :class="isZero(1, 3)">{{ data.board[1][3] }}</div>
            </div>
            <div class="game-cell grid20">
                <div class="game-block" :class="isZero(2, 0)">{{ data.board[2][0] }}</div>
            </div>
            <div class="game-cell grid21">
                <div class="game-block" :class="isZero(2, 1)">{{ data.board[2][1] }}</div>
            </div>
            <div class="game-cell grid22">
                <div class="game-block" :class="isZero(2, 2)">{{ data.board[2][2] }}</div>
            </div>
            <div class="game-cell grid23">
                <div class="game-block" :class="isZero(2, 3)">{{ data.board[2][3] }}</div>
            </div>
            <div class="game-cell grid30">
                <div class="game-block" :class="isZero(3, 0)">{{ data.board[3][0] }}</div>
            </div>
            <div class="game-cell grid31">
                <div class="game-block" :class="isZero(3, 1)">{{ data.board[3][1] }}</div>
            </div>
            <div class="game-cell grid32">
                <div class="game-block" :class="isZero(3, 2)">{{ data.board[3][2] }}</div>
            </div>
            <div class="game-cell grid33">
                <div class="game-block" :class="isZero(3, 3)">{{ data.board[3][3] }}</div>
            </div>
        </div>
    </div>
</template>
<style scope lang="scss">
.game {
    $cell-len: 64px;
    // display: flex;
    // flex-direction: column;
    .game-score {
        width: $cell-len * 37/8;
        background-color: #666;
    }
    .game-board {
        display: grid;
        width: $cell-len * 37/8;
        // height: 522px;
        padding: $cell-len/8;
        border-radius: $cell-len/16;
        background-color: #8d795f;
        grid:
            '. . . .'
            '. . . .'
            '. . . .'
            '. . . .';
        grid-gap: $cell-len/8 $cell-len/8;
        .game-cell {
            width: $cell-len;
            height: $cell-len;
            background-color: #567;
            border-radius: $cell-len/16;
            .game-block {
                width: inherit;
                height: inherit;
                text-align: center;
                line-height: $cell-len;
            }
            .game-block.hidden {
                visibility: hidden;
            }
        }
    }
}
</style>
